#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import re

from django.contrib.auth import get_user_model
from django_redis import get_redis_connection
from jwt.compat import text_type
from django.contrib.auth.hashers import make_password, check_password
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.tokens import RefreshToken

# from users.models import User
from users.models import Address
from celery_tasks.email.tasks import send_verify_email

User = get_user_model()


class CreateUserSerializer(serializers.ModelSerializer):
    """注册序列化器"""

    password_affirm = serializers.CharField(label="确认密码", write_only=True)  # 只做写入
    sms_code = serializers.CharField(label="短信验证码", write_only=True)
    allow = serializers.CharField(label="同意协议", write_only=True)
    token = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = [
            "id",
            "username",
            "password",
            "password_affirm",
            "sms_code",
            "mobile",
            "allow",
            "token",
        ]
        extra_kwargs = {
            "username": {
                "min_length": 5,
                "max_length": 20,
                "error_messages": {
                    "min_length": "仅允许5-20个字符的用户名",
                    "max_length": "仅允许5-20个字符的用户名",
                },
            },
            "password": {
                "write_only": True,
                "min_length": 8,
                "max_length": 20,
                "error_messages": {
                    "min_length": "仅允许8-20个字符的密码",
                    "max_length": "仅允许8-20个字符的密码",
                },
            },
            "mobile": {
                "write_only": True,
            },
        }

    def validate_mobile(self, value):
        """验证手机号"""
        if not re.match(r"^1[3-9]\d{9}$", value):
            raise serializers.ValidationError(f"{value} 手机号格式错误")
        return value

    def validate_allow(self, value):
        """校验用户是否同意协议"""
        if value != "true":
            raise serializers.ValidationError("请同意用户协议")
        return value

    def validate(self, data):
        """校验验证码及密码"""
        if data["password"] != data["password_affirm"]:
            raise serializers.ValidationError("输入的两次密码不一致")
        mobile = data["mobile"]
        sms_code = data["sms_code"]
        redis_conn = get_redis_connection("verify_codes")
        real_sms_code = redis_conn.get("sms_%s" % mobile)
        if real_sms_code is None:
            raise serializers.ValidationError("无效的短信验证码")
        if sms_code != real_sms_code.decode():  # 从redis取出数据来的时候是bytest需要转换一下
            raise serializers.ValidationError("短信验证码错误")
        return data

    def create(self, validated_data):
        """创建用户"""
        del_data = ["password_affirm", "sms_code", "allow"]
        for data in del_data:
            del validated_data[data]
        password = validated_data.pop("password")
        user = User(**validated_data)
        user.set_password(password)
        user.save()
        # 存储到数据库
        return user

    def get_token(self, user):
        tokens = RefreshToken.for_user(user)
        refresh = text_type(tokens)
        access = text_type(tokens.access_token)
        data = {"refresh": refresh, "access": access}
        return data


class MyTokenSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        """
        此方法往token的有效负载 payload 里面添加数据
        例如自定义了用户表结构，可以在这里面添加用户邮箱，头像图片地址，性别，年龄等可以公开的信息
        这部分放在token里面是可以被解析的，所以不要放比较私密的信息

        :param user: 用戶信息
        :return: token
        """
        token = super().get_token(user)
        # 添加个人信息
        token["name"] = user.username
        return token

    def validate(self, attrs):
        """
        此方法为响应数据结构处理
        原有的响应数据结构无法满足需求，在这里重写结构如下：
        {
            "refresh": "xxxx.xxxxx.xxxxx",
            "access": "xxxx.xxxx.xxxx",
            "expire": Token有效期截止时间,
            "username": "用户名",
            "email": "邮箱"
        }

        :param attrs: 請求參數
        :return: 响应数据
        """
        # data是个字典
        # 其结构为：{'refresh': '用于刷新token的令牌', 'access': '用于身份验证的Token值'}
        data = super().validate(attrs)
        # 加个token的键，值和access键一样
        data["token"] = data["access"]
        # # 然后把access键干掉
        del data["access"]
        del data["refresh"]
        # 令牌到期时间
        data["expire"] = self.get_token(self.user).access_token.payload["exp"]  # 有效期
        # 用户名
        data["username"] = self.user.username
        data["id"] = self.user.id
        return data


class UserDetailSerializer(serializers.ModelSerializer):
    """用户详细信息序列化器"""

    class Meta:
        model = User
        fields = ("id", "username", "mobile", "email", "email_active")


class EmailSerializer(serializers.ModelSerializer):
    """
    邮箱信息序列化器
    """

    class Meta:
        model = User
        fields = ("id", "email")
        extra_kwargs = {"email": {"required": True}}

    def update(self, instance, validated_data):
        instance.email = validated_data["email"]
        user = User(**validated_data)
        # token = self._make_token(user)
        # data = {
        #     "token": token,
        #     "user_id": user.id
        # }
        # send_verify_email.delay(instance.email, f"http://127.0.0.1:9000/user_center_info.html?token={str(data)}")
        instance.save()
        return instance

    @staticmethod
    def _make_token(user):
        """手动签发token"""
        from rest_framework_simplejwt.tokens import RefreshToken

        refresh = RefreshToken.for_user(user)
        return str(refresh.access_token)


class UserAddressSerializer(serializers.ModelSerializer):
    """
    用户地址序列化器
    """

    province = serializers.StringRelatedField(read_only=True)
    city = serializers.StringRelatedField(read_only=True)
    district = serializers.StringRelatedField(read_only=True)
    province_id = serializers.IntegerField(label="省ID", required=True)
    city_id = serializers.IntegerField(label="市ID", required=True)
    district_id = serializers.IntegerField(label="区ID", required=True)

    class Meta:
        model = Address
        exclude = ("user", "is_deleted", "create_time", "update_time")

    def validate_mobile(self, value):
        """
        验证手机号
        """
        if not re.match(r"^1[3-9]\d{9}$", value):
            raise serializers.ValidationError("手机号格式错误")
        return value

    def create(self, validated_data):
        """
        保存
        """
        validated_data["user"] = self.context["request"].user
        return super().create(validated_data)


class AddressTitleSerializer(serializers.ModelSerializer):
    """地址标题序列器"""

    class Meta:
        model = Address
        fields = ["title"]
